package kiven.jee.dao.hibernate.hibernate4;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;


import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import kiven.jee.dao.IBaseDao;
import kiven.jee.pagination.PageUtil;
import kiven.jee.utils.common.ReflectionUtil;

@Transactional(propagation=Propagation.REQUIRED)
@SuppressWarnings("unchecked")
public abstract class BaseHibernateDao<E extends Serializable, PK extends Serializable>
		implements IBaseDao<E, PK> {
	protected static final Logger lgger = LoggerFactory
			.getLogger(BaseHibernateDao.class);
	private final String HQL_LIST_ALL;
	private final String HQL_COUNT_ALL;
	private final String HQL_OPTIMIZE_PRE_LIST_ALL;
	private final String HQL_OPTIMEZE_NEXT_LIST_ALL;
	private Class<E> clazz;

	@Resource(name = "sessionFactory")
	private SessionFactory sessionFactory;

	private Session getSession() {
		// 事务必须是开启的(Required)，否则获取不到
		return sessionFactory.getCurrentSession();
	}

	public BaseHibernateDao() {
		clazz = ReflectionUtil.getSuperClassGenricType(getClass());

		HQL_COUNT_ALL = "select count(obj.id) from " + clazz.getSimpleName()
				+ " obj ";
		HQL_LIST_ALL = "from " + clazz.getSimpleName()
				+ " obj order by obj.id desc";
		HQL_OPTIMIZE_PRE_LIST_ALL = "from " + clazz.getSimpleName()
				+ " obj where obj.id > ? order by obj.id asc";
		HQL_OPTIMEZE_NEXT_LIST_ALL = "from " + clazz.getSimpleName()
				+ " obj where obj.id < ? order by obj.id desc";
	}

	@Override
	public boolean exists(PK id) {
		boolean flag = false;
		E entity = (E) this.getSession().get(clazz, id);

		if (entity != null) {
			flag = true;
		}
		return flag;
	}

	@Override
	public void save(E entity) {
		this.getSession().save(entity);
	}

	@Override
	public void remove(E entity) {
		this.getSession().delete(entity);

	}

	@Override
	public void removeById(PK id) {
		this.getSession().delete(this.findById(id));
	}

	@Override
	public void removeAllByIds(PK[] ids) {
		for (PK id : ids) {
			this.getSession().delete(this.findById(id));
		}
	}

	@Override
	public void update(E entity) {
		this.getSession().update(entity);
	}

	@Override
	public E findById(PK id) {
		return (E) this.getSession().get(clazz, id);
	}

	@Transactional
	@Override
	public List<E> findAll() {
		return listAll(HQL_LIST_ALL);
	}

	@Override
	public List<E> findAll(int pageNO, int pageSize) {
		return listAll(HQL_LIST_ALL, pageNO, pageSize);
	}

	@Override
	public List<E> pre(PK id, int pageNO, int pageSize) {
		if (id == null) {
			return this.listAll(this.HQL_OPTIMIZE_PRE_LIST_ALL, pageNO,
					pageSize);
		}

		return listAll(HQL_OPTIMIZE_PRE_LIST_ALL, pageNO, pageSize, id);

	}

	@Override
	public List<E> next(PK id, int pageNO, int pageSize) {
		if (id == null) {
			return this.listAll(this.HQL_OPTIMEZE_NEXT_LIST_ALL, pageNO,
					pageSize);
		}

		return listAll(this.HQL_OPTIMEZE_NEXT_LIST_ALL, pageNO, pageSize, id);
	}

	@Override
	public Integer getTotalAll() {
		return Integer.parseInt(this.getSession().createSQLQuery(HQL_COUNT_ALL)
				.list().get(0).toString());
	}

	/**
	 * 根据传入的hql语句查询数据
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	protected List<E> findAll(final String hql, final Object... paramList) {
		return listAll(hql, -1, -1, paramList);
	}

	protected List<E> listAll(String hql) {
		return this.getSession().createSQLQuery(hql).list();
	}

	protected List<E> listAll(final String hql, final int pageNO,
			final int pageSize, final Object... paramList) {
		Query query = getSession().createQuery(hql);
		setParameters(query, paramList);

		if (pageNO > -1 && pageSize > -1) {
			query.setMaxResults(pageSize);
			int start = PageUtil.getPageStart(pageNO, pageSize);

			if (start != 0)
				query.setFirstResult(start);
		}

		if (pageNO < 0) {
			query.setFirstResult(0);
		}

		return query.list();
	}
	
	/**
	 * 
	 * @param hql
	 * @param paramList
	 * @return
	 */
	@Transactional
	public E findUniqueByHql(String hql,Object... paramList) {
		Query query = createQuery(hql,paramList);
		return (E) query.uniqueResult();
	}

	/**
	 * 根据带 ? 占位符的查询语句及值对象，构造Query对象
	 * 
	 * @param hql
	 *            queryString 带?占位符的查询语句
	 * @param paramList
	 *            值对象
	 * @return
	 */
	@Transactional
	protected Query createQuery(String hql, Object... paramList) {
		Query queryObject = getSession().createQuery(hql);
		
		if (paramList != null) {
			for (int i = 0; i < paramList.length; i++) {
				queryObject.setParameter(i, paramList[i]);
			}
		}
		return queryObject;
	}
	
	/**
	 * 根据property 和 value 获得Entity
	 * 
	 * @param propertyName 属性名字
	 * @param value 值
	 * @return
	 */
	public E findUniqueByProperty(String propertyName, Object value) {
		Criteria criteria = getSession().createCriteria(clazz);

		return (E) criteria.add(Restrictions.eq(propertyName, value))
				.uniqueResult();
	}

	protected void setParameters(Query query, Object[] paramList) {
		if (paramList != null) {
			for (int i = 0; i < paramList.length; i++) {
				if (paramList[i] instanceof Date) {
					query.setTimestamp(i, (Date) paramList[i]);
				} else {
					query.setParameter(i, paramList[i]);
				}
			}
		}
	}

}
